package im.composer.media.sound.codec;

import java.io.IOException;
import java.util.Objects;

import javax.sound.sampled.AudioFormat;

import org.tritonus.dsp.interfaces.FloatSampleWriter;
import org.tritonus.share.sampled.FloatSampleBuffer;
import org.tritonus.share.sampled.file.AudioOutputStream;

public class FloatOutputStream implements AudioOutputStream, AutoCloseable, FloatSampleWriter, CommentSupport {

	private final AudioOutputStream out;
	private final FloatSampleWriter fsw;
	private long length;
	private AudioFormat format;

	public FloatOutputStream(AudioOutputStream out) {
		Objects.requireNonNull(out);
		this.out = out;
		fsw = null;
	}

	public FloatOutputStream(FloatSampleWriter fsw, AudioFormat format, long length) {
		Objects.requireNonNull(fsw);
		Objects.requireNonNull(format);
		this.fsw = fsw;
		this.format = format;
		this.length = length;
		out = null;
	}

	@Override
	public void write(FloatSampleBuffer buffer) throws IOException {
		write(buffer, 0, buffer.getSampleCount());
	}

	public void write(FloatSampleBuffer buffer, int offset, int sampleCount) throws IOException {
		if (sampleCount < 1) {
			return;
		}
		if (fsw != null) {
			fsw.write(buffer, offset, sampleCount);
		} else if (out != null) {
			int bSize = buffer.getByteArrayBufferSize(getFormat(), sampleCount);
			byte[] tempBuffer = new byte[bSize];
			buffer.convertToByteArray(offset, sampleCount, tempBuffer, 0, getFormat());
			write(tempBuffer, 0, bSize);
		} else {
			throw new NullPointerException();
		}
	}

	@Override
	public AudioFormat getFormat() {
		if (out != null) {
			return out.getFormat();
		}
		return format;
	}

	@Override
	public long getLength() {
		if (out != null) {
			return out.getLength();
		}
		return length;
	}

	public int write(byte[] abData) throws IOException {
		return write(abData, 0, abData.length);
	}

	@Override
	public int write(byte[] abData, int nOffset, int nLength) throws IOException {
		if (nLength < 1) {
			return 0;
		}
		if (out != null) {
			return out.write(abData, nOffset, nLength);
		} else if (fsw != null) {
			FloatSampleBuffer fsb = new FloatSampleBuffer(abData, nOffset, nLength, format);
			fsw.write(fsb);
			return nLength;
		} else {
			throw new NullPointerException();
		}
	}

	@Override
	public void close() throws IOException {
		if (out != null) {
			out.close();
		}
		if (fsw != null) {
			fsw.close();
		}
	}

	@Override
	public boolean addComment(String key, String value) {
		if (out != null && out instanceof CommentSupport) {
			return ((CommentSupport) out).addComment(key, value);
		}
		if (fsw != null && fsw instanceof CommentSupport) {
			return ((CommentSupport) fsw).addComment(key, value);
		}
		return false;
	}

}
